home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / comm / tcp / amitcptelnetf.lha / amitcp_telnet+ftp / telnet / commands.c next >
C/C++ Source or Header  |  1993-08-13  |  48KB  |  2,246 lines

  1. /*
  2.  * Copyright (c) 1988, 1990 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted provided
  6.  * that: (1) source distributions retain this entire copyright notice and
  7.  * comment, and (2) distributions including binaries display the following
  8.  * acknowledgement:  ``This product includes software developed by the
  9.  * University of California, Berkeley and its contributors'' in the
  10.  * documentation or other materials provided with the distribution and in
  11.  * all advertising materials mentioning features or use of this software.
  12.  * Neither the name of the University nor the names of its contributors may
  13.  * be used to endorse or promote products derived from this software without
  14.  * specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  16.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  17.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. #ifndef lint
  21. static char sccsid[] = "@(#)commands.c    5.1 (Berkeley) 9/14/90";
  22. #endif /* not lint */
  23.  
  24. #include <sys/types.h>
  25. #include <string.h>
  26. #include <sys/socket.h>
  27. #ifdef AMI_TCP
  28. #include <bsdsocket.h>
  29. #else
  30. #include <ss/socket.h>
  31. #endif
  32. #include <netinet/in.h>
  33.  
  34. #include <signal.h>
  35. #include <netdb.h>
  36. #include <ctype.h>
  37. #ifndef AMI_TCP
  38. #include <pwd.h>
  39. #endif
  40.  
  41. #ifdef __STDC__
  42. #include <stdarg.h>
  43. #else     
  44. #include <varargs.h>
  45. #endif     
  46. #include <arpa/telnet.h>
  47.  
  48. #include "general.h"
  49.  
  50. #include "ring.h"
  51.  
  52. #include "externs.h"
  53. #include "defines.h"
  54. #include "types.h"
  55.  
  56. char    *hostname;
  57. #ifdef AMI_TCP
  58. char    hostcopy[128];
  59. #endif
  60. extern char *getenv();
  61. extern long bytesin;
  62. extern long bytesout;
  63. extern FILE *log_file;
  64.  
  65. #define Ambiguous(s)    ((char **)s == &ambiguous)
  66. static char *ambiguous;        /* special return value for command routines */
  67. static call();
  68.  
  69. typedef struct {
  70.     char    *name;        /* command name */
  71.     char    *help;        /* help string (NULL for no help) */
  72.     int    (*handler)();    /* routine which executes command */
  73.     int    needconnect;    /* Do we need to be connected to execute? */
  74. } Command;
  75.  
  76. static char line[256];
  77. static char saveline[256];
  78. static int margc;
  79. static char *margv[20];
  80.  
  81. /*
  82.  * Various utility routines.
  83.  */
  84.  
  85.  
  86. char    *h_errlist[] = {
  87.     "Error 0",
  88.     "Unknown host",                /* 1 HOST_NOT_FOUND */
  89.     "Host name lookup failure",        /* 2 TRY_AGAIN */
  90.     "Unknown server error",            /* 3 NO_RECOVERY */
  91.     "No address associated with name",    /* 4 NO_ADDRESS */
  92. };
  93. int    h_nerr = { sizeof(h_errlist)/sizeof(h_errlist[0]) };
  94.  
  95. int h_errno;        /* In some version of SunOS this is necessary */
  96.  
  97. /*
  98.  * herror --
  99.  *    print the error indicated by the h_errno value.
  100.  */
  101. herror(s)
  102.     char *s;
  103. {
  104.     if (s && *s) {
  105.         fprintf(stderr, "%s: ", s);
  106.     }
  107.     if ((h_errno < 0) || (h_errno >= h_nerr)) {
  108.         fprintf(stderr, "Unknown error\n");
  109.     } else if (h_errno == 0) {
  110. #if    defined(sun)
  111.         fprintf(stderr, "Host unknown\n");
  112. #endif    /* defined(sun) */
  113.     } else {
  114.         fprintf(stderr, "%s\n", h_errlist[h_errno]);
  115.     }
  116. }
  117.  
  118. static void
  119. makeargv()
  120. {
  121.     register char *cp, *cp2, c;
  122.     register char **argp = margv;
  123.  
  124.     margc = 0;
  125.     cp = line;
  126.     while (c = *cp) {
  127.     register int inquote = 0;
  128.     while (isspace(c))
  129.         c = *++cp;
  130.     if (c == '\0')
  131.         break;
  132.     *argp++ = cp;
  133.     margc += 1;
  134.     for (cp2 = cp; c != '\0'; c = *++cp) {
  135.         if (inquote) {
  136.         if (c == inquote) {
  137.             inquote = 0;
  138.             continue;
  139.         }
  140.         } else {
  141.         if (c == '\\') {
  142.             if ((c = *++cp) == '\0')
  143.             break;
  144.         } else if (c == '"') {
  145.             inquote = '"';
  146.             continue;
  147.         } else if (c == '\'') {
  148.             inquote = '\'';
  149.             continue;
  150.         } else if (isspace(c))
  151.             break;
  152.         }
  153.         *cp2++ = c;
  154.     }
  155.     *cp2 = '\0';
  156.     if (c == '\0')
  157.         break;
  158.     cp++;
  159.     }
  160.     *argp++ = 0;
  161. }
  162.  
  163.  
  164. static char **
  165. genget(name, table, next)
  166. char    *name;        /* name to match */
  167. char    **table;        /* name entry in table */
  168. char    **(*next)();    /* routine to return next entry in table */
  169. {
  170.     register char *p, *q;
  171.     register char **c, **found;
  172.     register int nmatches, longest;
  173.  
  174.     if (name == 0) {
  175.         return 0;
  176.     }
  177.     longest = 0;
  178.     nmatches = 0;
  179.     found = 0;
  180.     for (c = table; (p = *c) != 0; c = (*next)(c)) {
  181.         for (q = name;
  182.             (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
  183.             if (*q == 0)        /* exact match? */
  184.                 return (c);
  185.         if (!*q) {            /* the name was a prefix */
  186.             if (q - name > longest) {
  187.                 longest = q - name;
  188.                 nmatches = 1;
  189.                 found = c;
  190.             } else if (q - name == longest)
  191.                 nmatches++;
  192.         }
  193.     }
  194.     if (nmatches > 1)
  195.         return &ambiguous;
  196.     return (found);
  197. }
  198.  
  199. /*
  200.  * Make a character string into a number.
  201.  *
  202.  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
  203.  */
  204.  
  205. static
  206. special(s)
  207. register char *s;
  208. {
  209.     register char c;
  210.     char b;
  211.  
  212.     switch (*s) {
  213.     case '^':
  214.         b = *++s;
  215.         if (b == '?') {
  216.             c = b | 0x40;        /* DEL */
  217.         } else {
  218.             c = b & 0x1f;
  219.         }
  220.         break;
  221.     default:
  222.         c = *s;
  223.         break;
  224.     }
  225.     return c;
  226. }
  227.  
  228. /*
  229.  * Construct a control character sequence
  230.  * for a special character.
  231.  */
  232. static char *
  233. control(c)
  234.     register cc_t c;
  235. {
  236.     static char buf[5];
  237.  
  238.     if (c == 0x7f)
  239.         return ("^?");
  240.     if (c == (cc_t)_POSIX_VDISABLE) {
  241.         return "off";
  242.     }
  243.     if ((unsigned int)c >= 0x80) {
  244.         buf[0] = '\\';
  245.         buf[1] = ((c>>6)&07) + '0';
  246.         buf[2] = ((c>>3)&07) + '0';
  247.         buf[3] = (c&07) + '0';
  248.         buf[4] = 0;
  249.     } else if ((unsigned int)c >= 0x20) {
  250.         buf[0] = c;
  251.         buf[1] = 0;
  252.     } else {
  253.         buf[0] = '^';
  254.         buf[1] = '@'+c;
  255.         buf[2] = 0;
  256.     }
  257.     return (buf);
  258. }
  259.  
  260.  
  261.  
  262. /*
  263.  *    The following are data structures and routines for
  264.  *    the "send" command.
  265.  *
  266.  */
  267.  
  268. struct sendlist {
  269.     char    *name;        /* How user refers to it (case independent) */
  270.     char    *help;        /* Help information (0 ==> no help) */
  271.     int        (*handler)();    /* Routine to perform (for special ops) */
  272.     int        what;        /* Character to be sent (<0 ==> special) */
  273. };
  274.  
  275. #define    SENDQUESTION    -1
  276. #define    SENDESCAPE    -3
  277.  
  278. static struct sendlist Sendlist[] = {
  279.     { "ao",    "Send Telnet Abort output",        0,    AO },
  280.     { "ayt",    "Send Telnet 'Are You There'",        0,    AYT },
  281.     { "brk",    "Send Telnet Break",            0,    BREAK },
  282.     { "ec",    "Send Telnet Erase Character",        0,    EC },
  283.     { "el",    "Send Telnet Erase Line",        0,    EL },
  284.     { "escape",    "Send current escape character",    0,    SENDESCAPE },
  285.     { "ga",    "Send Telnet 'Go Ahead' sequence",    0,    GA },
  286.     { "ip",    "Send Telnet Interrupt Process",    0,    IP },
  287.     { "nop",    "Send Telnet 'No operation'",        0,    NOP },
  288.     { "eor",    "Send Telnet 'End of Record'",        0,    EOR },
  289.     { "abort",    "Send Telnet 'Abort Process'",        0,    ABORT },
  290.     { "susp",    "Send Telnet 'Suspend Process'",    0,    SUSP },
  291.     { "eof",    "Send Telnet End of File Character",    0,    xEOF },
  292.     { "synch",    "Perform Telnet 'Synch operation'",    dosynch, SYNCH },
  293.     { "getstatus", "Send request for STATUS",        get_status, 0 },
  294.     { "?",    "Display send options",            0,    SENDQUESTION },
  295.     { 0 }
  296. };
  297.  
  298. static struct sendlist Sendlist2[] = {        /* some synonyms */
  299.     { "break",        0, 0, BREAK },
  300.  
  301.     { "intp",        0, 0, IP },
  302.     { "interrupt",    0, 0, IP },
  303.     { "intr",        0, 0, IP },
  304.  
  305.     { "help",        0, 0, SENDQUESTION },
  306.  
  307.     { 0 }
  308. };
  309.  
  310. static char **
  311. getnextsend(name)
  312. char *name;
  313. {
  314.     struct sendlist *c = (struct sendlist *) name;
  315.  
  316.     return (char **) (c+1);
  317. }
  318.  
  319. static struct sendlist *
  320. getsend(name)
  321. char *name;
  322. {
  323.     struct sendlist *sl;
  324.  
  325.     if ((sl = (struct sendlist *)
  326.             genget(name, (char **) Sendlist, getnextsend)) != 0) {
  327.     return sl;
  328.     } else {
  329.     return (struct sendlist *)
  330.                 genget(name, (char **) Sendlist2, getnextsend);
  331.     }
  332. }
  333.  
  334. static
  335. sendcmd(argc, argv)
  336. int    argc;
  337. char    **argv;
  338. {
  339.     int what;        /* what we are sending this time */
  340.     int count;        /* how many bytes we are going to need to send */
  341.     int i;
  342.     int question = 0;    /* was at least one argument a question */
  343.     struct sendlist *s;    /* pointer to current command */
  344.  
  345.     if (argc < 2) {
  346.     printf("need at least one argument for 'send' command\n");
  347.     printf("'send ?' for help\n");
  348.     return 0;
  349.     }
  350.     /*
  351.      * First, validate all the send arguments.
  352.      * In addition, we see how much space we are going to need, and
  353.      * whether or not we will be doing a "SYNCH" operation (which
  354.      * flushes the network queue).
  355.      */
  356.     count = 0;
  357.     for (i = 1; i < argc; i++) {
  358.     s = getsend(argv[i]);
  359.     if (s == 0) {
  360.         printf("Unknown send argument '%s'\n'send ?' for help.\n",
  361.             argv[i]);
  362.         return 0;
  363.     } else if (Ambiguous(s)) {
  364.         printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
  365.             argv[i]);
  366.         return 0;
  367.     }
  368.     switch (s->what) {
  369.     case SENDQUESTION:
  370.         question = 1;
  371.         break;
  372.     case SENDESCAPE:
  373.         count += 1;
  374.         break;
  375.     case SYNCH:
  376.         count += 2;
  377.         break;
  378.     default:
  379.         count += 2;
  380.         break;
  381.     }
  382.     }
  383.     if (!connected) {
  384.     if (count)
  385.         printf("?Need to be connected first.\n");
  386.     if (question) {
  387.         for (s = Sendlist; s->name; s++)
  388.         if (s->help)
  389.             printf("%-15s %s\n", s->name, s->help);
  390.     } else
  391.         printf("'send ?' for help\n");
  392.     return !question;
  393.     }
  394.     /* Now, do we have enough room? */
  395.     if (NETROOM() < count) {
  396.     printf("There is not enough room in the buffer TO the network\n");
  397.     printf("to process your request.  Nothing will be done.\n");
  398.     printf("('send synch' will throw away most data in the network\n");
  399.     printf("buffer, if this might help.)\n");
  400.     return 0;
  401.     }
  402.     /* OK, they are all OK, now go through again and actually send */
  403.     for (i = 1; i < argc; i++) {
  404.     if ((s = getsend(argv[i])) == 0) {
  405.         fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
  406.         (void) quit();
  407.         /*NOTREACHED*/
  408.     }
  409.     if (s->handler) {
  410.         (*s->handler)(s);
  411.     } else {
  412.         switch (what = s->what) {
  413.         case SYNCH:
  414.         dosynch();
  415.         break;
  416.         case SENDQUESTION:
  417.         for (s = Sendlist; s->name; s++) {
  418.             if (s->help)
  419.             printf("%-15s %s\n", s->name, s->help);
  420.         }
  421.         question = 1;
  422.         break;
  423.         case SENDESCAPE:
  424.         NETADD(escape);
  425.         break;
  426.         default:
  427.         NET2ADD(IAC, what);
  428.         printoption("SENT", "IAC", what);
  429.         break;
  430.         }
  431.     }
  432.     }
  433.     return !question;
  434. }
  435.  
  436. /*
  437.  * The following are the routines and data structures referred
  438.  * to by the arguments to the "toggle" command.
  439.  */
  440.  
  441. static
  442. lclchars()
  443. {
  444.     donelclchars = 1;
  445.     return 1;
  446. }
  447.  
  448. static
  449. togdebug()
  450. {
  451.     if (debug) {
  452.     if (net > 0 && 
  453. #ifdef AMI_TCP
  454.     setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) 
  455. #else
  456.     SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) 
  457. #endif
  458.     < 0)
  459.         perror("setsockopt (SO_DEBUG)");
  460.     } else
  461.     printf("Cannot turn off socket debugging\n");
  462.     return 1;
  463. }
  464.  
  465.  
  466. static int
  467. togcrlf()
  468. {
  469.     if (crlf) {
  470.     printf("Will send carriage returns as telnet <CR><LF>.\n");
  471.     } else {
  472.     printf("Will send carriage returns as telnet <CR><NUL>.\n");
  473.     }
  474.     return 1;
  475. }
  476.  
  477. int binmode;
  478.  
  479. static int
  480. togbinary(val)
  481. int val;
  482. {
  483.     donebinarytoggle = 1;
  484.  
  485.     if (val >= 0) {
  486.     binmode = val;
  487.     } else {
  488.     if (my_want_state_is_will(TELOPT_BINARY) &&
  489.                 my_want_state_is_do(TELOPT_BINARY)) {
  490.         binmode = 1;
  491.     } else if (my_want_state_is_wont(TELOPT_BINARY) &&
  492.                 my_want_state_is_dont(TELOPT_BINARY)) {
  493.         binmode = 0;
  494.     }
  495.     val = binmode ? 0 : 1;
  496.     }
  497.  
  498.     if (val == 1) {
  499.     if (my_want_state_is_will(TELOPT_BINARY) &&
  500.                     my_want_state_is_do(TELOPT_BINARY)) {
  501.         printf("Already operating in binary mode with remote host.\n");
  502.     } else {
  503.         printf("Negotiating binary mode with remote host.\n");
  504.         tel_enter_binary(3);
  505.     }
  506.     } else {
  507.     if (my_want_state_is_wont(TELOPT_BINARY) &&
  508.                     my_want_state_is_dont(TELOPT_BINARY)) {
  509.         printf("Already in network ascii mode with remote host.\n");
  510.     } else {
  511.         printf("Negotiating network ascii mode with remote host.\n");
  512.         tel_leave_binary(3);
  513.     }
  514.     }
  515.     return 1;
  516. }
  517.  
  518. static int
  519. togrbinary(val)
  520. int val;
  521. {
  522.     donebinarytoggle = 1;
  523.  
  524.     if (val == -1)
  525.     val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
  526.  
  527.     if (val == 1) {
  528.     if (my_want_state_is_do(TELOPT_BINARY)) {
  529.         printf("Already receiving in binary mode.\n");
  530.     } else {
  531.         printf("Negotiating binary mode on input.\n");
  532.         tel_enter_binary(1);
  533.     }
  534.     } else {
  535.     if (my_want_state_is_dont(TELOPT_BINARY)) {
  536.         printf("Already receiving in network ascii mode.\n");
  537.     } else {
  538.         printf("Negotiating network ascii mode on input.\n");
  539.         tel_leave_binary(1);
  540.     }
  541.     }
  542.     return 1;
  543. }
  544.  
  545. static int
  546. togxbinary(val)
  547. int val;
  548. {
  549.     donebinarytoggle = 1;
  550.  
  551.     if (val == -1)
  552.     val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
  553.  
  554.     if (val == 1) {
  555.     if (my_want_state_is_will(TELOPT_BINARY)) {
  556.         printf("Already transmitting in binary mode.\n");
  557.     } else {
  558.         printf("Negotiating binary mode on output.\n");
  559.         tel_enter_binary(2);
  560.     }
  561.     } else {
  562.     if (my_want_state_is_wont(TELOPT_BINARY)) {
  563.         printf("Already transmitting in network ascii mode.\n");
  564.     } else {
  565.         printf("Negotiating network ascii mode on output.\n");
  566.         tel_leave_binary(2);
  567.     }
  568.     }
  569.     return 1;
  570. }
  571.  
  572.  
  573. extern int togglehelp();
  574. extern int slc_check();
  575.  
  576. struct togglelist {
  577.     char    *name;        /* name of toggle */
  578.     char    *help;        /* help message */
  579.     int        (*handler)();    /* routine to do actual setting */
  580.     int        *variable;
  581.     char    *actionexplanation;
  582. };
  583.  
  584. static struct togglelist Togglelist[] = {
  585.     { "autoflush",
  586.     "flushing of output when sending interrupt characters",
  587.         0,
  588.         &autoflush,
  589.             "flush output when sending interrupt characters" },
  590.     { "autosynch",
  591.     "automatic sending of interrupt characters in urgent mode",
  592.         0,
  593.         &autosynch,
  594.             "send interrupt characters in urgent mode" },
  595.     { "binary",
  596.     "sending and receiving of binary data",
  597.         togbinary,
  598.         0,
  599.             0 },
  600.     { "inbinary",
  601.     "receiving of binary data",
  602.         togrbinary,
  603.         0,
  604.             0 },
  605.     { "outbinary",
  606.     "sending of binary data",
  607.         togxbinary,
  608.         0,
  609.             0 },
  610.     { "crlf",
  611.     "sending carriage returns as telnet <CR><LF>",
  612.         togcrlf,
  613.         &crlf,
  614.             0 },
  615.     { "crmod",
  616.     "mapping of received carriage returns",
  617.         0,
  618.         &crmod,
  619.             "map carriage return on output" },
  620.     { "localchars",
  621.     "local recognition of certain control characters",
  622.         lclchars,
  623.         &localchars,
  624.             "recognize certain control characters" },
  625.     { " ", "", 0 },        /* empty line */
  626.     { "debug",
  627.     "debugging",
  628.         togdebug,
  629.         &debug,
  630.             "turn on socket level debugging" },
  631.     { "netdata",
  632.     "printing of hexadecimal network data (debugging)",
  633.         0,
  634.         &netdata,
  635.             "print hexadecimal representation of network traffic" },
  636.     { "prettydump",
  637.     "output of \"netdata\" to user readable format (debugging)",
  638.         0,
  639.         &prettydump,
  640.             "print user readable output for \"netdata\"" },
  641.     { "options",
  642.     "viewing of options processing (debugging)",
  643.         0,
  644.         &showoptions,
  645.             "show option processing" },
  646.     { "?",
  647.     0,
  648.         togglehelp },
  649.     { "help",
  650.     0,
  651.         togglehelp },
  652.     { 0 }
  653. };
  654.  
  655. static
  656. togglehelp()
  657. {
  658.     struct togglelist *c;
  659.  
  660.     for (c = Togglelist; c->name; c++) {
  661.     if (c->help) {
  662.         if (*c->help)
  663.         printf("%-15s toggle %s\n", c->name, c->help);
  664.         else
  665.         printf("\n");
  666.     }
  667.     }
  668.     printf("\n");
  669.     printf("%-15s %s\n", "?", "display help information");
  670.     return 0;
  671. }
  672.  
  673. static
  674. settogglehelp(set)
  675. int set;
  676. {
  677.     struct togglelist *c;
  678.  
  679.     for (c = Togglelist; c->name; c++) {
  680.     if (c->help) {
  681.         if (*c->help)
  682.         printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
  683.                         c->help);
  684.         else
  685.         printf("\n");
  686.     }
  687.     }
  688. }
  689.  
  690. static char **
  691. getnexttoggle(name)
  692. char *name;
  693. {
  694.     struct togglelist *c = (struct togglelist *) name;
  695.  
  696.     return (char **) (c+1);
  697. }
  698.  
  699. static struct togglelist *
  700. gettoggle(name)
  701. char *name;
  702. {
  703.     return (struct togglelist *)
  704.             genget(name, (char **) Togglelist, getnexttoggle);
  705. }
  706.  
  707. static
  708. toggle(argc, argv)
  709. int    argc;
  710. char    *argv[];
  711. {
  712.     int retval = 1;
  713.     char *name;
  714.     struct togglelist *c;
  715.  
  716.     if (argc < 2) {
  717.     fprintf(stderr,
  718.         "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
  719.     return 0;
  720.     }
  721.     argc--;
  722.     argv++;
  723.     while (argc--) {
  724.     name = *argv++;
  725.     c = gettoggle(name);
  726.     if (Ambiguous(c)) {
  727.         fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
  728.                     name);
  729.         return 0;
  730.     } else if (c == 0) {
  731.         fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
  732.                     name);
  733.         return 0;
  734.     } else {
  735.         if (c->variable) {
  736.         *c->variable = !*c->variable;        /* invert it */
  737.         if (c->actionexplanation) {
  738.             printf("%s %s.\n", *c->variable? "Will" : "Won't",
  739.                             c->actionexplanation);
  740.         }
  741.         }
  742.         if (c->handler) {
  743.         retval &= (*c->handler)(-1);
  744.         }
  745.     }
  746.     }
  747.     return retval;
  748. }
  749.  
  750. /*
  751.  * The following perform the "set" command.
  752.  */
  753.  
  754. struct setlist {
  755.     char *name;                /* name */
  756.     char *help;                /* help information */
  757.     void (*handler)();
  758.     cc_t *charp;            /* where it is located at */
  759. };
  760.  
  761. static struct setlist Setlist[] = {
  762.     { "escape",    "character to escape back to telnet command mode", 0, &escape },
  763.         { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
  764.     { " ", "" },
  765.     { 0 }
  766. };
  767.  
  768. static char **
  769. getnextset(name)
  770. char *name;
  771. {
  772.     struct setlist *c = (struct setlist *)name;
  773.  
  774.     return (char **) (c+1);
  775. }
  776.  
  777. static struct setlist *
  778. getset(name)
  779. char *name;
  780. {
  781.     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
  782. }
  783.  
  784. set_escape_char(s)
  785. char *s;
  786. {
  787.     escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
  788.     printf("escape character is '%s'.\n", control(escape));
  789. }
  790.  
  791. static
  792. setcmd(argc, argv)
  793. int    argc;
  794. char    *argv[];
  795. {
  796.     int value;
  797.     struct setlist *ct;
  798.     struct togglelist *c;
  799.  
  800.     if (argc < 2 || argc > 3) {
  801.     printf("Format is 'set Name Value'\n'set ?' for help.\n");
  802.     return 0;
  803.     }
  804.     if ((argc == 2) &&
  805.         ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
  806.     for (ct = Setlist; ct->name; ct++)
  807.         printf("%-15s %s\n", ct->name, ct->help);
  808.     printf("\n");
  809.     settogglehelp(1);
  810.     printf("%-15s %s\n", "?", "display help information");
  811.     return 0;
  812.     }
  813.  
  814.     ct = getset(argv[1]);
  815.     if (ct == 0) {
  816.     c = gettoggle(argv[1]);
  817.     if (c == 0) {
  818.         fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
  819.             argv[1]);
  820.         return 0;
  821.     } else if (Ambiguous(c)) {
  822.         fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
  823.             argv[1]);
  824.         return 0;
  825.     }
  826.     if (c->variable) {
  827.         if ((argc == 2) || (strcmp("on", argv[2]) == 0))
  828.         *c->variable = 1;
  829.         else if (strcmp("off", argv[2]) == 0)
  830.         *c->variable = 0;
  831.         else {
  832.         printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
  833.         return 0;
  834.         }
  835.         if (c->actionexplanation) {
  836.         printf("%s %s.\n", *c->variable? "Will" : "Won't",
  837.                             c->actionexplanation);
  838.         }
  839.     }
  840.     if (c->handler)
  841.         (*c->handler)(1);
  842.     } else if (argc != 3) {
  843.     printf("Format is 'set Name Value'\n'set ?' for help.\n");
  844.     return 0;
  845.     } else if (Ambiguous(ct)) {
  846.     fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
  847.             argv[1]);
  848.     return 0;
  849.     } else if (ct->handler) {
  850.     (*ct->handler)(argv[2]);
  851.     printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
  852.     } else {
  853.     if (strcmp("off", argv[2])) {
  854.         value = special(argv[2]);
  855.     } else {
  856.         value = _POSIX_VDISABLE;
  857.     }
  858.     *(ct->charp) = (cc_t)value;
  859.     printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
  860.     }
  861.     slc_check();
  862.     return 1;
  863. }
  864.  
  865. static
  866. unsetcmd(argc, argv)
  867. int    argc;
  868. char    *argv[];
  869. {
  870.     struct setlist *ct;
  871.     struct togglelist *c;
  872.     register char *name;
  873.  
  874.     if (argc < 2) {
  875.     fprintf(stderr,
  876.         "Need an argument to 'unset' command.  'unset ?' for help.\n");
  877.     return 0;
  878.     }
  879.     if ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help"))) {
  880.     for (ct = Setlist; ct->name; ct++)
  881.         printf("%-15s %s\n", ct->name, ct->help);
  882.     printf("\n");
  883.     settogglehelp(0);
  884.     printf("%-15s %s\n", "?", "display help information");
  885.     return 0;
  886.     }
  887.  
  888.     argc--;
  889.     argv++;
  890.     while (argc--) {
  891.     name = *argv++;
  892.     ct = getset(name);
  893.     if (ct == 0) {
  894.         c = gettoggle(name);
  895.         if (c == 0) {
  896.         fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
  897.             name);
  898.         return 0;
  899.         } else if (Ambiguous(c)) {
  900.         fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
  901.             name);
  902.         return 0;
  903.         }
  904.         if (c->variable) {
  905.         *c->variable = 0;
  906.         if (c->actionexplanation) {
  907.             printf("%s %s.\n", *c->variable? "Will" : "Won't",
  908.                             c->actionexplanation);
  909.         }
  910.         }
  911.         if (c->handler)
  912.         (*c->handler)(0);
  913.     } else if (Ambiguous(ct)) {
  914.         fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
  915.             name);
  916.         return 0;
  917.     } else if (ct->handler) {
  918.         (*ct->handler)(0);
  919.         printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
  920.     } else {
  921.         *(ct->charp) = _POSIX_VDISABLE;
  922.         printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
  923.     }
  924.     }
  925.     return 1;
  926. }
  927.  
  928. /*
  929.  * The following are the data structures and routines for the
  930.  * 'mode' command.
  931.  */
  932.  
  933. static
  934. dolinemode()
  935. {
  936.     send_will(TELOPT_LINEMODE, 1);
  937.     send_dont(TELOPT_ECHO, 1);
  938.     return 1;
  939. }
  940.  
  941. static
  942. docharmode()
  943. {
  944.     send_wont(TELOPT_LINEMODE, 1);
  945.     send_do(TELOPT_ECHO, 1);
  946.     return 1;
  947. }
  948.  
  949. setmode(bit)
  950. {
  951.     return dolmmode(bit, 1);
  952. }
  953.  
  954. clearmode(bit)
  955. {
  956.     return dolmmode(bit, 0);
  957. }
  958.  
  959. dolmmode(bit, on)
  960. int bit, on;
  961. {
  962.     char c;
  963.     extern int linemode;
  964.  
  965.     if (my_want_state_is_wont(TELOPT_LINEMODE)) {
  966.     printf("?Need to have LINEMODE option enabled first.\n");
  967.     printf("'mode ?' for help.\n");
  968.     return 0;
  969.     }
  970.  
  971.     if (on)
  972.     c = (linemode | bit);
  973.     else
  974.     c = (linemode & ~bit);
  975.     lm_mode(&c, 1, 1);
  976.     return 1;
  977. }
  978.  
  979. struct modelist {
  980.     char    *name;        /* command name */
  981.     char    *help;        /* help string */
  982.     int    (*handler)();    /* routine which executes command */
  983.     int    needconnect;    /* Do we need to be connected to execute? */
  984.     int    arg1;
  985. };
  986.  
  987. extern int modehelp();
  988.  
  989. static struct modelist ModeList[] = {
  990.     { "character", "Disable LINEMODE option",    docharmode, 1 },
  991.     { "line",    "Enable LINEMODE option",    dolinemode, 1 },
  992.     { "", "", 0 },
  993.     { "",    "These require the LINEMODE option to be enabled", 0 },
  994.     { "isig",    "Enable signal trapping",    setmode, 1, MODE_TRAPSIG },
  995.     { "+isig",    0,                setmode, 1, MODE_TRAPSIG },
  996.     { "-isig",    "Disable signal trapping",    clearmode, 1, MODE_TRAPSIG },
  997.     { "edit",    "Enable character editing",    setmode, 1, MODE_EDIT },
  998.     { "+edit",    0,                setmode, 1, MODE_EDIT },
  999.     { "-edit",    "Disable character editing",    clearmode, 1, MODE_EDIT },
  1000.     { "softtabs", "Enable tab expansion",    setmode, 1, MODE_SOFT_TAB },
  1001.     { "+softtabs", 0,                setmode, 1, MODE_SOFT_TAB },
  1002.     { "-softtabs", "Disable character editing",    clearmode, 1, MODE_SOFT_TAB },
  1003.     { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO },
  1004.     { "+litecho", 0,                setmode, 1, MODE_LIT_ECHO },
  1005.     { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
  1006.     { "help",    0,                modehelp, 0 },
  1007.     { "", "", 0 },
  1008.     { "?",    "Print help information",    modehelp, 0 },
  1009.     { 0 },
  1010. };
  1011.  
  1012. static char **
  1013. getnextmode(name)
  1014. char *name;
  1015. {
  1016.     return (char **) (((struct modelist *)name)+1);
  1017. }
  1018.  
  1019. static struct modelist *
  1020. getmodecmd(name)
  1021. char *name;
  1022. {
  1023.     return (struct modelist *) genget(name, (char **) ModeList, getnextmode);
  1024. }
  1025.  
  1026. modehelp()
  1027. {
  1028.     struct modelist *mt;
  1029.  
  1030.     printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
  1031.     for (mt = ModeList; mt->name; mt++) {
  1032.     if (mt->help) {
  1033.         if (*mt->help)
  1034.         printf("%-15s %s\n", mt->name, mt->help);
  1035.         else
  1036.         printf("\n");
  1037.     }
  1038.     }
  1039.     return 0;
  1040. }
  1041.  
  1042. static
  1043. modecmd(argc, argv)
  1044. int    argc;
  1045. char    *argv[];
  1046. {
  1047.     struct modelist *mt;
  1048.  
  1049.     if (argc != 2) {
  1050.     printf("'mode' command requires an argument\n");
  1051.     printf("'mode ?' for help.\n");
  1052.     } else if ((mt = getmodecmd(argv[1])) == 0) {
  1053.     fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
  1054.     } else if (Ambiguous(mt)) {
  1055.     fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
  1056.     } else if (mt->needconnect && !connected) {
  1057.     printf("?Need to be connected first.\n");
  1058.     printf("'mode ?' for help.\n");
  1059.     } else if (mt->handler) {
  1060.     return (*mt->handler)(mt->arg1);
  1061.     }
  1062.     return 0;
  1063. }
  1064.  
  1065. /*
  1066.  * The following data structures and routines implement the
  1067.  * "display" command.
  1068.  */
  1069.  
  1070. static
  1071. display(argc, argv)
  1072. int    argc;
  1073. char    *argv[];
  1074. {
  1075. #define    dotog(tl)    if (tl->variable && tl->actionexplanation) { \
  1076.                 if (*tl->variable) { \
  1077.                 printf("will"); \
  1078.                 } else { \
  1079.                 printf("won't"); \
  1080.                 } \
  1081.                 printf(" %s.\n", tl->actionexplanation); \
  1082.             }
  1083.  
  1084. #define    doset(sl)   if (sl->name && *sl->name != ' ') { \
  1085.             if (sl->handler == 0) \
  1086.                 printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
  1087.             else \
  1088.                 printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
  1089.             }
  1090.  
  1091.     struct togglelist *tl;
  1092.     struct setlist *sl;
  1093.  
  1094.     if (argc == 1) {
  1095.     for (tl = Togglelist; tl->name; tl++) {
  1096.         dotog(tl);
  1097.     }
  1098.     printf("\n");
  1099.     for (sl = Setlist; sl->name; sl++) {
  1100.         doset(sl);
  1101.     }
  1102.     } else {
  1103.     int i;
  1104.  
  1105.     for (i = 1; i < argc; i++) {
  1106.         sl = getset(argv[i]);
  1107.         tl = gettoggle(argv[i]);
  1108.         if (Ambiguous(sl) || Ambiguous(tl)) {
  1109.         printf("?Ambiguous argument '%s'.\n", argv[i]);
  1110.         return 0;
  1111.         } else if (!sl && !tl) {
  1112.         printf("?Unknown argument '%s'.\n", argv[i]);
  1113.         return 0;
  1114.         } else {
  1115.         if (tl) {
  1116.             dotog(tl);
  1117.         }
  1118.         if (sl) {
  1119.             doset(sl);
  1120.         }
  1121.         }
  1122.     }
  1123.     }
  1124. /*@*/optionstatus();
  1125.     return 1;
  1126. #undef    doset
  1127. #undef    dotog
  1128. }
  1129.  
  1130. /*
  1131.  * The following are the data structures, and many of the routines,
  1132.  * relating to command processing.
  1133.  */
  1134.  
  1135. /*
  1136.  * Set the escape character.
  1137.  */
  1138. static
  1139. setescape(argc, argv)
  1140.     int argc;
  1141.     char *argv[];
  1142. {
  1143.     register char *arg;
  1144.     char buf[50];
  1145.  
  1146.     printf(
  1147.         "Deprecated usage - please use 'set escape%s%s' in the future.\n",
  1148.                 (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
  1149.     if (argc > 2)
  1150.         arg = argv[1];
  1151.     else {
  1152.         printf("new escape character: ");
  1153.         (void) gets(buf);
  1154.         arg = buf;
  1155.     }
  1156.     if (arg[0] != '\0')
  1157.         escape = arg[0];
  1158.         printf("Escape character is '%s'.\n", control(escape));
  1159.     (void) fflush(stdout);
  1160.     return 1;
  1161. }
  1162.  
  1163. /*VARARGS*/
  1164. static
  1165. togcrmod()
  1166. {
  1167.     crmod = !crmod;
  1168.     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
  1169.     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
  1170.     (void) fflush(stdout);
  1171.     return 1;
  1172. }
  1173.  
  1174. /*VARARGS*/
  1175. suspend()
  1176. {
  1177.     return 1;
  1178. }
  1179.  
  1180. /*VARARGS*/
  1181. static
  1182. bye(argc, argv)
  1183. int    argc;        /* Number of arguments */
  1184. char    *argv[];    /* arguments */
  1185. {
  1186.     if (connected) {
  1187.     (void) shutdown(net, 2);
  1188.     printf("Connection closed.\n");
  1189.     (void) NetClose(net);
  1190.     if (log_file) fprintf(log_file,"%s %d\n",hostname,bytesin+bytesout);
  1191.     connected = 0;
  1192.     /* reset options */
  1193.     tninit();
  1194.     }
  1195.     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
  1196.     longjmp(toplevel, 1);
  1197.     /* NOTREACHED */
  1198.     }
  1199.     return 1;            /* Keep lint, etc., happy */
  1200. }
  1201.  
  1202. /*VARARGS*/
  1203. quit()
  1204. {
  1205.     (void) call(bye, "bye", "fromquit", 0);
  1206.     Exit(0);
  1207.     /*NOTREACHED*/
  1208. }
  1209.  
  1210. /*
  1211.  * The SLC command.
  1212.  */
  1213.  
  1214. struct slclist {
  1215.     char    *name;
  1216.     char    *help;
  1217.     int    (*handler)();
  1218.     int    arg;
  1219. };
  1220.  
  1221. extern int slc_help();
  1222. extern int slc_mode_export(), slc_mode_import(), slcstate();
  1223.  
  1224. struct slclist SlcList[] = {
  1225.     { "export",    "Use local special character definitions",
  1226.                         slc_mode_export,    0 },
  1227.     { "import",    "Use remote special character definitions",
  1228.                         slc_mode_import,    1 },
  1229.     { "check",    "Verify remote special character definitions",
  1230.                         slc_mode_import,    0 },
  1231.     { "help",    0,                slc_help,        0 },
  1232.     { "?",    "Print help information",    slc_help,        0 },
  1233.     { 0 },
  1234. };
  1235.  
  1236. static
  1237. slc_help()
  1238. {
  1239.     struct slclist *c;
  1240.  
  1241.     for (c = SlcList; c->name; c++) {
  1242.     if (c->help) {
  1243.         if (*c->help)
  1244.         printf("%-15s %s\n", c->name, c->help);
  1245.         else
  1246.         printf("\n");
  1247.     }
  1248.     }
  1249. }
  1250.  
  1251. static char **
  1252. getnextslc(name)
  1253. char *name;
  1254. {
  1255.     return (char **)(((struct slclist *)name)+1);
  1256. }
  1257.  
  1258. static struct slclist *
  1259. getslc(name)
  1260. char *name;
  1261. {
  1262.     return (struct slclist *)genget(name, (char **) SlcList, getnextslc);
  1263. }
  1264.  
  1265. static
  1266. slccmd(argc, argv)
  1267. int    argc;
  1268. char    *argv[];
  1269. {
  1270.     struct slclist *c;
  1271.  
  1272.     if (argc != 2) {
  1273.     fprintf(stderr,
  1274.         "Need an argument to 'slc' command.  'slc ?' for help.\n");
  1275.     return 0;
  1276.     }
  1277.     c = getslc(argv[1]);
  1278.     if (c == 0) {
  1279.         fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
  1280.                     argv[1]);
  1281.         return 0;
  1282.     }
  1283.     if (Ambiguous(c)) {
  1284.         fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
  1285.                     argv[1]);
  1286.         return 0;
  1287.     }
  1288.     (*c->handler)(c->arg);
  1289.     slcstate();
  1290.     return 1;
  1291. }
  1292.  
  1293. /*
  1294.  * The ENVIRON command.
  1295.  */
  1296.  
  1297. struct envlist {
  1298.     char    *name;
  1299.     char    *help;
  1300.     int    (*handler)();
  1301.     int    narg;
  1302. };
  1303.  
  1304. extern struct env_lst *env_define();
  1305. extern int env_undefine();
  1306. extern int env_export(), env_unexport();
  1307. extern int env_send(), env_list(), env_help();
  1308.  
  1309. struct envlist EnvList[] = {
  1310.     { "define",    "Define an environment variable",
  1311.                         (int (*)())env_define,    2 },
  1312.     { "undefine", "Undefine an environment variable",
  1313.                         env_undefine,    1 },
  1314.     { "export",    "Mark an environment variable for automatic export",
  1315.                         env_export,    1 },
  1316.     { "unexport", "Dont mark an environment variable for automatic export",
  1317.                         env_unexport,    1 },
  1318.     { "send",    "Send an environment variable", env_send,    1 },
  1319.     { "list",    "List the current environment variables",
  1320.                         env_list,    0 },
  1321.     { "help",    0,                env_help,        0 },
  1322.     { "?",    "Print help information",    env_help,        0 },
  1323.     { 0 },
  1324. };
  1325.  
  1326. static
  1327. env_help()
  1328. {
  1329.     struct envlist *c;
  1330.  
  1331.     for (c = EnvList; c->name; c++) {
  1332.     if (c->help) {
  1333.         if (*c->help)
  1334.         printf("%-15s %s\n", c->name, c->help);
  1335.         else
  1336.         printf("\n");
  1337.     }
  1338.     }
  1339. }
  1340.  
  1341. static char **
  1342. getnextenv(name)
  1343. char *name;
  1344. {
  1345.     return (char **)(((struct envlist *)name)+1);
  1346. }
  1347.  
  1348. static struct envlist *
  1349. getenvcmd(name)
  1350. char *name;
  1351. {
  1352.     return (struct envlist *)genget(name, (char **) EnvList, getnextenv);
  1353. }
  1354.  
  1355. env_cmd(argc, argv)
  1356. int    argc;
  1357. char    *argv[];
  1358. {
  1359.     struct envlist *c;
  1360.  
  1361.     if (argc < 2) {
  1362.     fprintf(stderr,
  1363.         "Need an argument to 'environ' command.  'environ ?' for help.\n");
  1364.     return 0;
  1365.     }
  1366.     c = getenvcmd(argv[1]);
  1367.     if (c == 0) {
  1368.         fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
  1369.                     argv[1]);
  1370.         return 0;
  1371.     }
  1372.     if (Ambiguous(c)) {
  1373.         fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
  1374.                     argv[1]);
  1375.         return 0;
  1376.     }
  1377.     if (c->narg + 2 != argc) {
  1378.     fprintf(stderr,
  1379.         "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
  1380.         c->narg < argc + 2 ? "only " : "",
  1381.         c->narg, c->narg == 1 ? "" : "s", c->name);
  1382.     return 0;
  1383.     }
  1384.     (void)(*c->handler)(argv[2], argv[3]);
  1385.     return 1;
  1386. }
  1387.  
  1388. struct env_lst {
  1389.     struct env_lst *next;    /* pointer to next structure */
  1390.     struct env_lst *prev;    /* pointer to next structure */
  1391.     char *var;        /* pointer to variable name */
  1392.     char *value;        /* pointer to varialbe value */
  1393.     int export;        /* 1 -> export with default list of variables */
  1394. };
  1395.  
  1396. struct env_lst envlisthead;
  1397.  
  1398. struct env_lst *
  1399. env_find(var)
  1400. char *var;
  1401. {
  1402.     register struct env_lst *ep;
  1403.  
  1404.     for (ep = envlisthead.next; ep; ep = ep->next) {
  1405.         if (strcmp(ep->var, var) == 0)
  1406.             return(ep);
  1407.     }
  1408.     return(NULL);
  1409. }
  1410.  
  1411. env_init()
  1412. {
  1413.     register char **epp, *cp;
  1414.     register struct env_lst *ep;
  1415.  
  1416.     /*
  1417.      * If USER is not defined, but LOGNAME is, then add
  1418.      * USER with the value from LOGNAME.  By default, we
  1419.      * don't export the USER variable.
  1420.      */
  1421.     if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
  1422.         env_define("USER", ep->value);
  1423.         env_unexport("USER");
  1424.     }
  1425.     env_export("DISPLAY");
  1426.     env_export("PRINTER");
  1427. }
  1428.  
  1429. struct env_lst *
  1430. env_define(var, value)
  1431. char *var, *value;
  1432. {
  1433.     register struct env_lst *ep;
  1434.     extern char *strdup();
  1435.  
  1436.     if (ep = env_find(var)) {
  1437.         if (ep->var)
  1438.             free(ep->var);
  1439.         if (ep->value)
  1440.             free(ep->value);
  1441.     } else {
  1442.         ep = (struct env_lst *)malloc(sizeof(struct env_lst));
  1443.         ep->next = envlisthead.next;
  1444.         envlisthead.next = ep;
  1445.         ep->prev = &envlisthead;
  1446.         if (ep->next)
  1447.             ep->next->prev = ep;
  1448.     }
  1449.     ep->export = 1;
  1450.     ep->var = strdup(var);
  1451.     ep->value = strdup(value);
  1452.     return(ep);
  1453. }
  1454.  
  1455. env_undefine(var)
  1456. char *var;
  1457. {
  1458.     register struct env_lst *ep;
  1459.  
  1460.     if (ep = env_find(var)) {
  1461.         ep->prev->next = ep->next;
  1462.         if (ep->next)
  1463.             ep->next->prev = ep->prev;
  1464.         if (ep->var)
  1465.             free(ep->var);
  1466.         if (ep->value)
  1467.             free(ep->value);
  1468.         free(ep);
  1469.     }
  1470. }
  1471.  
  1472. env_export(var)
  1473. char *var;
  1474. {
  1475.     register struct env_lst *ep;
  1476.  
  1477.     if (ep = env_find(var))
  1478.         ep->export = 1;
  1479. }
  1480.  
  1481. env_unexport(var)
  1482. char *var;
  1483. {
  1484.     register struct env_lst *ep;
  1485.  
  1486.     if (ep = env_find(var))
  1487.         ep->export = 0;
  1488. }
  1489.  
  1490. env_send(var)
  1491. char *var;
  1492. {
  1493.     register struct env_lst *ep;
  1494.  
  1495.         if (my_state_is_wont(TELOPT_ENVIRON)) {
  1496.         fprintf(stderr,
  1497.             "Cannot send '%s': Telnet ENVIRON option not enabled\n",
  1498.                                     var);
  1499.         return;
  1500.     }
  1501.     ep = env_find(var);
  1502.     if (ep == 0) {
  1503.         fprintf(stderr, "Cannot send '%s': variable not defined\n",
  1504.                                     var);
  1505.         return;
  1506.     }
  1507.     env_opt_start_info();
  1508.     env_opt_add(ep->var);
  1509.     env_opt_end(0);
  1510. }
  1511.  
  1512. env_list()
  1513. {
  1514.     register struct env_lst *ep;
  1515.  
  1516.     for (ep = envlisthead.next; ep; ep = ep->next) {
  1517.         printf("%c %-20s %s\n", ep->export ? '*' : ' ',
  1518.                     ep->var, ep->value);
  1519.     }
  1520. }
  1521.  
  1522. char *
  1523. env_default(init)
  1524. {
  1525.     static struct env_lst *nep = NULL;
  1526.  
  1527.     if (init) {
  1528.         nep = &envlisthead;
  1529.         return;
  1530.     }
  1531.     if (nep) {
  1532.         while (nep = nep->next) {
  1533.             if (nep->export)
  1534.                 return(nep->var);
  1535.         }
  1536.     }
  1537.     return(NULL);
  1538. }
  1539.  
  1540. char *
  1541. env_getvalue(var)
  1542. char *var;
  1543. {
  1544.     register struct env_lst *ep;
  1545.  
  1546.     if (ep = env_find(var))
  1547.         return(ep->value);
  1548.     return(NULL);
  1549. }
  1550.  
  1551. /*
  1552.  * Print status about the connection.
  1553.  */
  1554. /*ARGSUSED*/
  1555. static
  1556. status(argc, argv)
  1557. int    argc;
  1558. char    *argv[];
  1559. {
  1560.     if (connected) {
  1561.     printf("Connected to %s.\n", hostname);
  1562.     if ((argc < 2) || strcmp(argv[1], "notmuch")) {
  1563.         int mode = getconnmode();
  1564.  
  1565.         if (my_want_state_is_will(TELOPT_LINEMODE)) {
  1566.         printf("Operating with LINEMODE option\n");
  1567.         printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
  1568.         printf("%s catching of signals\n",
  1569.                     (mode&MODE_TRAPSIG) ? "Local" : "No");
  1570.         slcstate();
  1571.         } else {
  1572.         printf("Operating in single character mode\n");
  1573.         if (localchars)
  1574.             printf("Catching signals locally\n");
  1575.         }
  1576.         printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
  1577.         if (my_want_state_is_will(TELOPT_LFLOW))
  1578.         printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
  1579.     }
  1580.     } else {
  1581.     printf("No connection.\n");
  1582.     }
  1583.     printf("Escape character is '%s'.\n", control(escape));
  1584.     (void) fflush(stdout);
  1585.     return 1;
  1586. }
  1587.  
  1588.  
  1589. extern    int autologin;
  1590.  
  1591. int
  1592. tn(argc, argv)
  1593.     int argc;
  1594.     char *argv[];
  1595. {
  1596.     register struct hostent *host = 0;
  1597.     struct sockaddr_in sin;
  1598.     struct servent *sp = 0;
  1599.     static char    hnamebuf[32];
  1600.     unsigned long temp, inet_addr();
  1601.     extern char *inet_ntoa();
  1602. #if    defined(SRCRT) && defined(IPPROTO_IP)
  1603.     char *srp = 0, *strrchr();
  1604.     unsigned long sourceroute(), srlen;
  1605. #endif
  1606.     char *cmd, *hostp = 0, *portp = 0, *user = 0;
  1607.  
  1608.     /* clear the socket address prior to use */
  1609.     bzero((char *)&sin, sizeof(sin));
  1610.  
  1611.     if (connected) {
  1612.     printf("?Already connected to %s\n", hostname);
  1613.     return 0;
  1614.     }
  1615.     if (argc < 2) {
  1616.     (void) strcpy(line, "Connect ");
  1617.     printf("(to) ");
  1618.     (void) gets(&line[strlen(line)]);
  1619.     makeargv();
  1620.     argc = margc;
  1621.     argv = margv;
  1622.     }
  1623.     cmd = *argv;
  1624.     --argc; ++argv;
  1625.     while (argc) {
  1626.     if (strcmp(*argv, "-l") == 0) {
  1627.         --argc; ++argv;
  1628.         if (argc == 0)
  1629.         goto usage;
  1630.         user = *argv++;
  1631.         --argc;
  1632.         continue;
  1633.     }
  1634.     if (strcmp(*argv, "-a") == 0) {
  1635.         --argc; ++argv;
  1636.         autologin = 1;
  1637.         continue;
  1638.     }
  1639.     if (hostp == 0) {
  1640.         hostp = *argv++;
  1641.         --argc;
  1642.         continue;
  1643.     }
  1644.     if (portp == 0) {
  1645.         portp = *argv++;
  1646.         --argc;
  1647.         continue;
  1648.     }
  1649.     usage:
  1650.     printf("usage: %s [-l user] [-a] host-name [port]\n", cmd);
  1651.     return 0;
  1652.     }
  1653. #if    defined(SRCRT) && defined(IPPROTO_IP)
  1654.     if (hostp[0] == '@' || hostp[0] == '!') {
  1655.     if ((hostname = strrchr(hostp, ':')) == NULL)
  1656.         hostname = strrchr(hostp, '@');
  1657.     hostname++;
  1658.     srp = 0;
  1659.     temp = sourceroute(hostp, &srp, &srlen);
  1660.     if (temp == 0) {
  1661.         herror(srp);
  1662.         return 0;
  1663.     } else if (temp == -1) {
  1664.         printf("Bad source route option: %s\n", hostp);
  1665.         return 0;
  1666.     } else {
  1667.         sin.sin_addr.s_addr = temp;
  1668.         sin.sin_family = AF_INET;
  1669.     }
  1670.     } else {
  1671. #endif
  1672.     temp = inet_addr(hostp);
  1673.     if (temp != (unsigned long) -1) {
  1674.         sin.sin_addr.s_addr = temp;
  1675.         sin.sin_family = AF_INET;
  1676.         (void) strcpy(hnamebuf, hostp);
  1677.         hostname = hnamebuf;
  1678.     } else {
  1679.         host = gethostbyname(hostp);
  1680.         if (host) {
  1681.         sin.sin_family = host->h_addrtype;
  1682.         memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
  1683. #ifdef AMI_TCP
  1684.         strcpy(hostcopy,host->h_name);
  1685.         hostname = hostcopy;
  1686. #else
  1687.         hostname = host->h_name;
  1688. #endif
  1689.         } else {
  1690.         herror(hostp);
  1691.         return 0;
  1692.         }
  1693.     }
  1694. #if    defined(SRCRT) && defined(IPPROTO_IP)
  1695.     }
  1696. #endif
  1697.     if (portp) {
  1698.     if (*portp == '-') {
  1699.         portp++;
  1700.         telnetport = 1;
  1701.     } else
  1702.         telnetport = 0;
  1703.     sin.sin_port = atoi(portp);
  1704.     if (sin.sin_port == 0) {
  1705.         sp = getservbyname(portp, "tcp");
  1706.         if (sp)
  1707.         sin.sin_port = sp->s_port;
  1708.         else {
  1709.         printf("%s: bad port number\n", portp);
  1710.         return 0;
  1711.         }
  1712.     } else {
  1713. #if    !defined(htons)
  1714.         u_short htons();
  1715. #endif    /* !defined(htons) */
  1716.         sin.sin_port = htons(sin.sin_port);
  1717.     }
  1718.     } else {
  1719.     if (sp == 0) {
  1720.         sp = getservbyname("telnet", "tcp");
  1721.         if (sp == 0) {
  1722.         fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
  1723.         return 0;
  1724.         }
  1725.         sin.sin_port = sp->s_port;
  1726.     }
  1727.     telnetport = 1;
  1728.     }
  1729.     bytesin = 0;
  1730.     bytesout = 0;
  1731. #ifdef AMI_TCP    
  1732.     printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
  1733. #else
  1734.     printf("Trying %s...\n", inet_ntoa(sin.sin_addr.s_addr));
  1735. #endif
  1736.     do {
  1737.     net = socket(AF_INET, SOCK_STREAM, 0);
  1738.     if (net < 0) {
  1739.         perror("telnet: socket");
  1740.         return 0;
  1741.     }
  1742. #if    defined(SRCRT) && defined(IPPROTO_IP)
  1743.     if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
  1744.         perror("setsockopt (IP_OPTIONS)");
  1745. #endif
  1746.  
  1747.     if (debug && 
  1748. #ifdef AMI_TCP
  1749.     setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug,sizeof(debug)) 
  1750. #else
  1751.     SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) 
  1752. #endif
  1753.     < 0) {
  1754.         perror("setsockopt (SO_DEBUG)");
  1755.     }
  1756.  
  1757.     if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
  1758.         perror("telnet: Unable to connect to remote host");
  1759.         return 0;
  1760.     }
  1761.     connected++;
  1762.     } while (connected == 0);
  1763.     cmdrc(hostp, hostname);
  1764.     if (autologin && user == NULL) {
  1765. #ifdef AMI_TCP
  1766.     user = getenv("USER");
  1767. #else
  1768.     struct passwd *pw;
  1769.     if (user == NULL ||
  1770.         (pw = getpwnam(user)) && pw->pw_uid != getuid()) {
  1771.         if (pw = getpwuid(getuid()))
  1772.             user = pw->pw_name;
  1773.         else
  1774.             user = NULL;
  1775.     }
  1776. #endif
  1777.     }
  1778.     if (user) {
  1779.     env_define("USER", user);
  1780.     env_export("USER");
  1781.     }
  1782.     (void) call(status, "status", "notmuch", 0);
  1783.     if (setjmp(peerdied) == 0)
  1784.     telnet();
  1785.     (void) NetClose(net);
  1786.     if (log_file) fprintf(log_file,"%s %d\n",hostname,bytesin+bytesout);
  1787.     ExitString("Connection closed by foreign host.\n",1);
  1788.     /*NOTREACHED*/
  1789. }
  1790.  
  1791. controld()
  1792. {
  1793.         NETADD(4);
  1794. }
  1795.  
  1796. controlc()
  1797. {
  1798.         NETADD(3);
  1799. }
  1800.  
  1801. #define HELPINDENT (sizeof ("connect"))
  1802.  
  1803. static char
  1804.     openhelp[] =    "connect to a site",
  1805.     closehelp[] =    "close current connection",
  1806.     quithelp[] =    "exit telnet",
  1807.     statushelp[] =    "print status information",
  1808.     helphelp[] =    "print help information",
  1809.     sendhelp[] =    "transmit special characters ('send ?' for more)",
  1810.     sethelp[] =     "set operating parameters ('set ?' for more)",
  1811.     unsethelp[] =     "unset operating parameters ('unset ?' for more)",
  1812.     togglestring[] ="toggle operating parameters ('toggle ?' for more)",
  1813.     slchelp[] =    "change state of special charaters ('slc ?' for more)",
  1814.     displayhelp[] =    "display operating parameters",
  1815.     controlhelp[] = "send a control character to host",
  1816.     envhelp[] =    "change environment variables ('environ ?' for more)",
  1817.     modestring[] = "try to enter line or character mode ('mode ?' for more)";
  1818.  
  1819. extern int    help();
  1820.  
  1821. static Command cmdtab[] = {
  1822.     { "close",    closehelp,    bye,        1 },
  1823.     { "^d",    controlhelp,    controld,    1 },
  1824.     { "^c",    controlhelp,    controlc,    1 },
  1825.     { "display",    displayhelp,    display,    0 },
  1826.     { "mode",    modestring,    modecmd,    0 },
  1827.     { "open",    openhelp,    tn,        0 },
  1828.     { "quit",    quithelp,    quit,        0 },
  1829.     { "send",    sendhelp,    sendcmd,    0 },
  1830.     { "set",    sethelp,    setcmd,        0 },
  1831.     { "unset",    unsethelp,    unsetcmd,    0 },
  1832.     { "status",    statushelp,    status,        0 },
  1833.     { "toggle",    togglestring,    toggle,        0 },
  1834.     { "slc",    slchelp,    slccmd,        0 },
  1835.     { "environ",    envhelp,    env_cmd,    0 },
  1836.     { "?",        helphelp,    help,        0 },
  1837.     0
  1838. };
  1839.  
  1840. static char    crmodhelp[] =    "deprecated command -- use 'toggle crmod' instead";
  1841. static char    escapehelp[] =    "deprecated command -- use 'set escape' instead";
  1842.  
  1843. static Command cmdtab2[] = {
  1844.     { "help",    0,        help,        0 },
  1845.     { "escape",    escapehelp,    setescape,    0 },
  1846.     { "crmod",    crmodhelp,    togcrmod,    0 },
  1847.     0
  1848. };
  1849.  
  1850.  
  1851. /*
  1852.  * Call routine with argc, argv set from args (terminated by 0).
  1853.  */
  1854.  
  1855. /*VARARGS1*/
  1856. typedef int (*intrtn_t)();
  1857. static
  1858. #ifdef __STDC__
  1859. int call  (intrtn_t routine, ...)
  1860. #else     
  1861. call(va_alist)
  1862. va_dcl
  1863. #endif  
  1864. {
  1865.     va_list ap;
  1866. #ifndef __STDC__
  1867.     intrtn_t routine;
  1868. #endif  
  1869.     char *args[100];
  1870.     int argno = 0;
  1871.  
  1872. #ifdef __STDC__
  1873.     va_start(ap, routine);
  1874. #else     
  1875.     va_start(ap);
  1876.     routine = (va_arg(ap, intrtn_t));
  1877. #endif  
  1878.     while ((args[argno++] = va_arg(ap, char *)) != 0) {
  1879.     ;
  1880.     }
  1881.     va_end(ap);
  1882.     return (*routine)(argno-1, args);
  1883. }
  1884.  
  1885.  
  1886. static char **
  1887. getnextcmd(name)
  1888. char *name;
  1889. {
  1890.     Command *c = (Command *) name;
  1891.  
  1892.     return (char **) (c+1);
  1893. }
  1894.  
  1895. static Command *
  1896. getcmd(name)
  1897. char *name;
  1898. {
  1899.     Command *cm;
  1900.  
  1901.     if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
  1902.     return cm;
  1903.     } else {
  1904.     return (Command *) genget(name, (char **) cmdtab2, getnextcmd);
  1905.     }
  1906. }
  1907.  
  1908. void
  1909. command(top, tbuf, cnt)
  1910.     int top;
  1911.     char *tbuf;
  1912.     int cnt;
  1913. {
  1914.     register Command *c;
  1915.  
  1916.     setcommandmode();
  1917.     if (!top) {
  1918.     putchar('\n');
  1919.     }
  1920.     for (;;) {
  1921.     printf("%s> ", prompt);
  1922.     if (tbuf) {
  1923.         register char *cp;
  1924.         cp = line;
  1925.         while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
  1926.         cnt--;
  1927.         tbuf = 0;
  1928.         if (cp == line || *--cp != '\n' || cp == line)
  1929.         goto getline;
  1930.         *cp = '\0';
  1931.         printf("%s\n", line);
  1932.     } else {
  1933.     getline:
  1934.         if (gets(line) == NULL) {
  1935.         if (feof(stdin) || ferror(stdin)) {
  1936.             (void) quit();
  1937.             /*NOTREACHED*/
  1938.         }
  1939.         break;
  1940.         }
  1941.     }
  1942.     if (line[0] == 0)
  1943.         break;
  1944.     makeargv();
  1945.     if (margv[0] == 0) {
  1946.         break;
  1947.     }
  1948.     c = getcmd(margv[0]);
  1949.     if (Ambiguous(c)) {
  1950.         printf("?Ambiguous command\n");
  1951.         continue;
  1952.     }
  1953.     if (c == 0) {
  1954.         printf("?Invalid command\n");
  1955.         continue;
  1956.     }
  1957.     if (c->needconnect && !connected) {
  1958.         printf("?Need to be connected first.\n");
  1959.         continue;
  1960.     }
  1961.     if ((*c->handler)(margc, margv)) {
  1962.         break;
  1963.     }
  1964.     }
  1965.     if (!top) {
  1966.     if (!connected) {
  1967.         longjmp(toplevel, 1);
  1968.         /*NOTREACHED*/
  1969.     }
  1970.     setconnmode(0);
  1971.     }
  1972. }
  1973.  
  1974. /*
  1975.  * Help command.
  1976.  */
  1977. static
  1978. help(argc, argv)
  1979.     int argc;
  1980.     char *argv[];
  1981. {
  1982.     register Command *c;
  1983.  
  1984.     if (argc == 1) {
  1985.         printf("Commands may be abbreviated.  Commands are:\n\n");
  1986.         for (c = cmdtab; c->name; c++)
  1987.             if (c->help) {
  1988.                 printf("%-*s\t%s\n", HELPINDENT, c->name,
  1989.                                     c->help);
  1990.             }
  1991.         return 0;
  1992.     }
  1993.     while (--argc > 0) {
  1994.         register char *arg;
  1995.         arg = *++argv;
  1996.         c = getcmd(arg);
  1997.         if (Ambiguous(c))
  1998.             printf("?Ambiguous help command %s\n", arg);
  1999.         else if (c == (Command *)0)
  2000.             printf("?Invalid help command %s\n", arg);
  2001.         else
  2002.             printf("%s\n", c->help);
  2003.     }
  2004.     return 0;
  2005. }
  2006.  
  2007. static char *rcname = 0;
  2008. static char rcbuf[128];
  2009.  
  2010. cmdrc(m1, m2)
  2011.     char *m1, *m2;
  2012. {
  2013.     register Command *c;
  2014.     FILE *rcfile;
  2015.     int gotmachine = 0;
  2016.     int l1 = strlen(m1);
  2017.     int l2 = strlen(m2);
  2018.     char m1save[64];
  2019.  
  2020.     strcpy(m1save, m1);
  2021.     m1 = m1save;
  2022.  
  2023.     if (rcname == 0) {
  2024.     rcname = getenv("HOME");
  2025.     if (rcname)
  2026.         strcpy(rcbuf, rcname);
  2027.     else
  2028.         rcbuf[0] = '\0';
  2029.     strcat(rcbuf, "/.telnetrc");
  2030.     rcname = rcbuf;
  2031.     }
  2032.  
  2033.     if ((rcfile = fopen(rcname, "r")) == 0) {
  2034.     return;
  2035.     }
  2036.  
  2037.     for (;;) {
  2038.     if (fgets(line, sizeof(line), rcfile) == NULL)
  2039.         break;
  2040.     if (line[0] == 0)
  2041.         break;
  2042.     if (line[0] == '#')
  2043.         continue;
  2044.     if (gotmachine == 0) {
  2045.         if (isspace(line[0]))
  2046.         continue;
  2047.         if (strncasecmp(line, m1, l1) == 0)
  2048.         strncpy(line, &line[l1], sizeof(line) - l1);
  2049.         else if (strncasecmp(line, m2, l2) == 0)
  2050.         strncpy(line, &line[l2], sizeof(line) - l2);
  2051.         else
  2052.         continue;
  2053.         gotmachine = 1;
  2054.     } else {
  2055.         if (!isspace(line[0])) {
  2056.         gotmachine = 0;
  2057.         continue;
  2058.         }
  2059.     }
  2060.     makeargv();
  2061.     if (margv[0] == 0)
  2062.         continue;
  2063.     c = getcmd(margv[0]);
  2064.     if (Ambiguous(c)) {
  2065.         printf("?Ambiguous command: %s\n", margv[0]);
  2066.         continue;
  2067.     }
  2068.     if (c == 0) {
  2069.         printf("?Invalid command: %s\n", margv[0]);
  2070.         continue;
  2071.     }
  2072.     /*
  2073.      * This should never happen...
  2074.      */
  2075.     if (c->needconnect && !connected) {
  2076.         printf("?Need to be connected first for %s.\n", margv[0]);
  2077.         continue;
  2078.     }
  2079.     (*c->handler)(margc, margv);
  2080.     }
  2081.     fclose(rcfile);
  2082. }
  2083.  
  2084. #if    defined(SRCRT) && defined(IPPROTO_IP)
  2085.  
  2086. /*
  2087.  * Source route is handed in as
  2088.  *    [!]@hop1@hop2...[@|:]dst
  2089.  * If the leading ! is present, it is a
  2090.  * strict source route, otherwise it is
  2091.  * assmed to be a loose source route.
  2092.  *
  2093.  * We fill in the source route option as
  2094.  *    hop1,hop2,hop3...dest
  2095.  * and return a pointer to hop1, which will
  2096.  * be the address to connect() to.
  2097.  *
  2098.  * Arguments:
  2099.  *    arg:    pointer to route list to decipher
  2100.  *
  2101.  *    cpp:     If *cpp is not equal to NULL, this is a
  2102.  *        pointer to a pointer to a character array
  2103.  *        that should be filled in with the option.
  2104.  *
  2105.  *    lenp:    pointer to an integer that contains the
  2106.  *        length of *cpp if *cpp != NULL.
  2107.  *
  2108.  * Return values:
  2109.  *
  2110.  *    Returns the address of the host to connect to.  If the
  2111.  *    return value is -1, there was a syntax error in the
  2112.  *    option, either unknown characters, or too many hosts.
  2113.  *    If the return value is 0, one of the hostnames in the
  2114.  *    path is unknown, and *cpp is set to point to the bad
  2115.  *    hostname.
  2116.  *
  2117.  *    *cpp:    If *cpp was equal to NULL, it will be filled
  2118.  *        in with a pointer to our static area that has
  2119.  *        the option filled in.  This will be 32bit aligned.
  2120.  * 
  2121.  *    *lenp:    This will be filled in with how long the option
  2122.  *        pointed to by *cpp is.
  2123.  *    
  2124.  */
  2125. unsigned long
  2126. sourceroute(arg, cpp, lenp)
  2127. char    *arg;
  2128. char    **cpp;
  2129. int    *lenp;
  2130. {
  2131.     static char lsr[44];
  2132.     char *cp, *cp2, *lsrp, *lsrep, *index();
  2133.     register int tmp;
  2134.     struct in_addr sin_addr;
  2135.     register struct hostent *host = 0;
  2136.     register char c;
  2137.  
  2138.     /*
  2139.      * Verify the arguments, and make sure we have
  2140.      * at least 7 bytes for the option.
  2141.      */
  2142.     if (cpp == NULL || lenp == NULL)
  2143.         return((unsigned long)-1);
  2144.     if (*cpp != NULL && *lenp < 7)
  2145.         return((unsigned long)-1);
  2146.     /*
  2147.      * Decide whether we have a buffer passed to us,
  2148.      * or if we need to use our own static buffer.
  2149.      */
  2150.     if (*cpp) {
  2151.         lsrp = *cpp;
  2152.         lsrep = lsrp + *lenp;
  2153.     } else {
  2154.         *cpp = lsrp = lsr;
  2155.         lsrep = lsrp + 44;
  2156.     }
  2157.  
  2158.     cp = arg;
  2159.  
  2160.     /*
  2161.      * Next, decide whether we have a loose source
  2162.      * route or a strict source route, and fill in
  2163.      * the begining of the option.
  2164.      */
  2165.     if (*cp == '!') {
  2166.         cp++;
  2167.         *lsrp++ = IPOPT_SSRR;
  2168.     } else
  2169.         *lsrp++ = IPOPT_LSRR;
  2170.  
  2171.     if (*cp != '@')
  2172.         return((unsigned long)-1);
  2173.  
  2174.     lsrp++;        /* skip over length, we'll fill it in later */
  2175.     *lsrp++ = 4;
  2176.  
  2177.     cp++;
  2178.  
  2179.     sin_addr.s_addr = 0;
  2180.  
  2181.     for (c = 0;;) {
  2182.         if (c == ':')
  2183.             cp2 = 0;
  2184.         else for (cp2 = cp; c = *cp2; cp2++) {
  2185.             if (c == ',') {
  2186.                 *cp2++ = '\0';
  2187.                 if (*cp2 == '@')
  2188.                     cp2++;
  2189.             } else if (c == '@') {
  2190.                 *cp2++ = '\0';
  2191.             } else if (c == ':') {
  2192.                 *cp2++ = '\0';
  2193.             } else
  2194.                 continue;
  2195.             break;
  2196.         }
  2197.         if (!c)
  2198.             cp2 = 0;
  2199.  
  2200.         if ((tmp = inet_addr(cp)) != -1) {
  2201.             sin_addr.s_addr = tmp;
  2202.         } else if (host = gethostbyname(cp)) {
  2203.             memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length);
  2204.         } else {
  2205.             *cpp = cp;
  2206.             return(0);
  2207.         }
  2208.         memcpy(lsrp, (char *)&sin_addr, 4);
  2209.         lsrp += 4;
  2210.         if (cp2)
  2211.             cp = cp2;
  2212.         else
  2213.             break;
  2214.         /*
  2215.          * Check to make sure there is space for next address
  2216.          */
  2217.         if (lsrp + 4 > lsrep)
  2218.             return((unsigned long)-1);
  2219.     }
  2220.     if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
  2221.         *cpp = 0;
  2222.         *lenp = 0;
  2223.         return((unsigned long)-1);
  2224.     }
  2225.     *lsrp++ = IPOPT_NOP; /* 32 bit word align it */
  2226.     *lenp = lsrp - *cpp;
  2227.     return(sin_addr.s_addr);
  2228. }
  2229. #endif
  2230.  
  2231. #if    defined(NOSTRNCASECMP)
  2232. strncasecmp(p1, p2, len)
  2233. register char *p1, *p2;
  2234. int len;
  2235. {
  2236.     while (len--) {
  2237.     if (tolower(*p1) != tolower(*p2))
  2238.        return(tolower(*p1) - tolower(*p2));
  2239.     if (*p1 == '\0')
  2240.         return(0);
  2241.     p1++, p2++;
  2242.     }
  2243.     return(0);
  2244. }
  2245. #endif
  2246.